#include <stdlib.h>
#include <stdio.h>
#include <nds.h>
#include <xlibrary.h>

// global headers
#include "common.h"

// local headers
#include "zone.h"
#include "video_window.h"

#include "layout.h"

sLayout *l_new(u32 flags, sZone *zone) {
	sLayout *lay=(sLayout *)xcalloc(1, sizeof(sLayout));
	lay->content=z_copy(zone);
	lay->flags=flags;

	return lay;
}

sLayout *l_append(sLayout *lay, u32 flags, sZone *zone) {
	sLayout *curlay=l_getLast(lay);
	if(!curlay) return NULL;

	curlay->next=l_new((curlay->flags & fL_COPY_MASK) | (flags & ~fL_COPY_MASK), zone);
	curlay->next->prev=curlay;
	curlay->next->parent=curlay->parent;

	return curlay->next;
}

sLayout *l_addChild(sLayout *lay, u32 flags, sZone *zone) {
	if(lay->child) {
		return l_append(lay->child, flags, zone);
	}
	else {
		lay->child=l_new(flags, zone);
		lay->child->parent=lay;
		return lay->child;
	}
}

sLayout *l_getFirst(sLayout *lay) {
	while(lay) {
		if(!lay->prev) break;
		lay=lay->prev;
	}
	return lay;
}

sLayout *l_getLast(sLayout *lay) {
	while(lay) {
		if(!lay->next) break;
		lay=lay->next;
	}
	return lay;
}

sLGeometry _l_getGeometry(sLayout *lay) {	// be carefull this function don't verify pointers, to speed up process
	sLGeometry lgeo={
		.width=0,
		.height=0,
		.numspacer=0
	};

	sLGeometry _lgeo={
		.width=0,
		.height=0,
		.numspacer=0
	};

	sLayout *curlay=l_getFirst(lay);
	while(curlay) {
		if(curlay->child) {
			_lgeo=_l_getGeometry(curlay->child);
		}
		else {
			if(curlay->content) {
				_lgeo.width=curlay->content->width;
				_lgeo.height=curlay->content->height;

				if(
					( (lay->flags & fL_HORIZONTAL) && !(curlay->content->flags & fZ_FIXEDWIDTH )) ||
					(!(lay->flags & fL_HORIZONTAL) && !(curlay->content->flags & fZ_FIXEDHEIGHT))
				) {	// a non-fixed size element is shown as a spacer
					lgeo.numspacer++;
				}
			}
			else {
				lgeo.numspacer++;
			}
		}

		if(lay->flags & fL_HORIZONTAL) {	// horizontal layout
			lgeo.width+=_lgeo.width;
			lgeo.height=MAX(lgeo.height, _lgeo.height);
		}
		else {	// vertical layout
			lgeo.width=MAX(lgeo.width, _lgeo.width);
			lgeo.height+=_lgeo.height;
		}

		curlay=curlay->next;
	}

	return lgeo;
}

sLGeometry l_getGeometry(sLayout *lay) {
	if(!lay) return (sLGeometry){0, 0, 0};

	return _l_getGeometry(lay);
}

int _l_render(sLayout *lay, u16 width, u16 height) {	// be carefull this function don't verify pointers, to speed up process
// added width and added height to the regular geometry
printf("\nw=%d, h=%d", width, height);

	sLayout *curlay=l_getFirst(lay);
	sLGeometry lgeo, sgeo;

	lgeo=_l_getGeometry(lay);
printf("\nlo=%c, lw=%d, lh=%d, lns=%d", (lay->flags & fL_HORIZONTAL)?'H':'V', lgeo.width, lgeo.height, lgeo.numspacer);
	if(!lgeo.width || !lgeo.height) return 0;			// there's nothing to draw

	if(width==(u16)-1) width=lgeo.width;
	if(height==(u16)-1) height=lgeo.height;

	if(lgeo.numspacer) {
		if(lay->flags & fL_HORIZONTAL) {				// horizontal layout
			sgeo.width=(width-lgeo.width)/lgeo.numspacer;
			sgeo.height=0;
		}
		else {											// vertical layout
			sgeo.width=0;
			sgeo.height=(height-lgeo.height)/lgeo.numspacer;
		}
	}
	else {
		if(lay->flags & fL_HORIZONTAL) {				// horizontal layout
			video_addStartPosition((width-lgeo.width)>>1, 0);
		}
		else {											// vertical layout
			video_addStartPosition(0, (height-lgeo.height)>>1);
		}
		video_gotoStartPosition();

		sgeo.width=0;
		sgeo.height=0;
	}
printf("\nsw=%d, sh=%d", sgeo.width, sgeo.height);

	while(curlay) {	// start drawing
		if(curlay->child) {	// this layout have a child list of layouts
			if(lay->flags & fL_HORIZONTAL) {
				if(_l_render(curlay->child, (u16)-1/* on change rien */, height)) return 1;
			}
			else {
				if(_l_render(curlay->child, width, (u16)-1/* on change rien */)) return 1;
			}
		}
		else {
			if(curlay->content) {	// this layout isn't a spacer, it has content
				if(lay->flags & fL_HORIZONTAL) {
					if(curlay->content->flags & fZ_FIXEDWIDTH) {
						if(z_render(curlay->content, 0, height-lgeo.height)) return 1;
						video_addStartPosition(curlay->content->width, 0);
					}
					else {
						if(z_render(curlay->content, sgeo.width, height-lgeo.height)) return 1;
						video_addStartPosition(curlay->content->width+sgeo.width, 0);
					}
				}
				else {
					if(curlay->content->flags & fZ_FIXEDHEIGHT) {
						if(z_render(curlay->content, width-lgeo.width, 0)) return 1;
						video_addStartPosition(0, curlay->content->height);
					}
					else {
						if(z_render(curlay->content, width-lgeo.width, sgeo.height)) return 1;
						video_addStartPosition(0, curlay->content->height+sgeo.height);
					}
				}
			}
			else {	// this layout is a spacer
				video_addStartPosition(sgeo.width, sgeo.height);	// one of the two size will be 0
			}
		}

		video_gotoStartPosition();

		curlay=curlay->next;
	}

	return 0;
}

int l_render(sLayout *lay, u16 width, u16 height) {
	if(!lay) return 1;

	return _l_render(lay, width, height);
}

